package cn.zch.cmbchina.util.httputils;
import cn.zch.cmbchina.util.constant.ConstantStr;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.TreeMap;
/***
 * 请求工具类
 * @author zch
 * 2019/7/8
 * @version V0.0.1.201907081829.01
 */
@Slf4j
public class XbHttpUtils {
  /**
   * httpGo
   *
   * @param url                      url
   * @param requestMethod            请求方法 POST GET
   *                                 HttpClient中可设置三个超时：
   * @param connectTimeout           ConnectTimeout（建立连接的超时）、
   * @param connectionRequestTimeout connectionRequestTimeout RequestTimeout（连接池获取到连接的超时时间）、
   * @param socketTimeout            SocketTimeout（获取数据的超时时间）。
   * @param redirectsEnabled         redirectsEnabled 允许自动重定向
   */
  public static String httpRequest(String url, String requestMethod, int connectTimeout, int connectionRequestTimeout, int socketTimeout, boolean redirectsEnabled) {
    CloseableHttpClient httpClient = HttpClients.createDefault();
    String result;
    // @formatter:off
    RequestConfig requestConfig = RequestConfig.custom().
      setConnectTimeout(connectTimeout).
      setConnectionRequestTimeout(connectionRequestTimeout).
      setSocketTimeout(socketTimeout).
      setRedirectsEnabled(redirectsEnabled).build();
    // @formatter:on
    if ("POST".equals(requestMethod)) {
      HttpPost post = new HttpPost(url);
      post.setConfig(requestConfig);
      try {
        HttpResponse response = httpClient.execute(post);
        if (response.getStatusLine().getStatusCode() == 200) {
          result = EntityUtils.toString(response.getEntity());
          return result;
        }
        else {
          log.error("请求失败：" + response.getStatusLine().getStatusCode());
          return "请求失败";
        }
      }
      catch (Exception e) {
        String errMsg = e.getMessage();
        boolean connectionRefused = (errMsg.contains(ConstantStr.CONNECTION) && errMsg.contains(ConstantStr.REFUSED));
        boolean readTimeOut = errMsg.contains("Read timed out");
        if (connectionRefused) {
          log.warn(errMsg);
        }
        else if (readTimeOut) {
          log.warn(errMsg);
        }
        else {
          log.error(errMsg);
        }
        return "请求失败";
      }
      finally {
        try {
          httpClient.close();
        }
        catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    else {
      HttpGet get = new HttpGet(url);
      String charset;
      get.setConfig(requestConfig);
      try {
        HttpResponse response = httpClient.execute(get);
        // print("toString:" + response.toString());
        if (response.getStatusLine().getStatusCode() == 200) {
          HttpEntity entity = response.getEntity();
          charset = getContentCharSet(entity);
          // 使用EntityUtils的toString方法，传递编码，默认编码是ISO-8859-1
          result = EntityUtils.toString(entity, charset);
          return result;
        }
        else {
          log.error("请求失败：" + response.getStatusLine().getStatusCode());
          return "请求失败";
        }
      }
      catch (Exception e) {
        log.error(e.getMessage(), e);
        // e.printStackTrace() 此句慎用
        String errMsg = e.getMessage();
        boolean connectionRefused = (errMsg.contains(ConstantStr.CONNECTION) && errMsg.contains(ConstantStr.REFUSED));
        boolean readTimeOut = errMsg.contains("Read timed out");
        if (connectionRefused) {
          log.warn(errMsg);
        }
        else if (readTimeOut) {
          log.warn(errMsg);
        }
        else {
          log.error(errMsg);
        }
        return "请求失败";
      }
      finally {
        try {
          httpClient.close();
        }
        catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
  /**
   * 封装 httpclient 参数
   */
  public static String httpRequest(HttpPost post, HttpGet get, String requestMethod, int connectTimeout, int connectionRequestTimeout, int socketTimeout, boolean redirectsEnabled) {
    CloseableHttpClient httpClient = HttpClients.createDefault();
    String result;
    // @formatter:off
    RequestConfig requestConfig = RequestConfig.custom().
      setConnectTimeout(connectTimeout).
      setConnectionRequestTimeout(connectionRequestTimeout).
      setSocketTimeout(socketTimeout).
      setRedirectsEnabled(redirectsEnabled).build();
    // @formatter:on
    if ("POST".equals(requestMethod)) {
      //HttpPost post = new HttpPost(url);
      post.setConfig(requestConfig);
      try {
        HttpResponse response = httpClient.execute(post);
        if (response.getStatusLine().getStatusCode() == 200) {
          result = EntityUtils.toString(response.getEntity());
          return result;
        }
        else {
          log.error("请求失败：" + response.getStatusLine().getStatusCode());
          return "请求失败";
        }
      }
      catch (Exception e) {
        String errMsg = e.getMessage();
        boolean connectionRefused = (errMsg.contains(ConstantStr.CONNECTION) && errMsg.contains(ConstantStr.REFUSED));
        boolean readTimeOut = errMsg.contains("Read timed out");
        if (connectionRefused) {
          log.warn(errMsg);
        }
        else if (readTimeOut) {
          log.warn(errMsg);
        }
        else {
          log.error(errMsg);
        }
        return "请求失败";
      }
      finally {
        try {
          httpClient.close();
        }
        catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    else {
      get.setConfig(requestConfig);
      try {
        HttpResponse response = httpClient.execute(get);
        // print("toString:" + response.toString());
        if (response.getStatusLine().getStatusCode() == 200) {
          HttpEntity entity = response.getEntity();
          result = EntityUtils.toString(entity, "UTF-8");
          return result;
        }
        else {
          log.error("请求失败：" + response.getStatusLine().getStatusCode());
          return "请求失败";
        }
      }
      catch (Exception e) {
        log.error(e.getMessage(), e);
        // e.printStackTrace() 此句慎用
        String errMsg = e.getMessage();
        boolean connectionRefused = (errMsg.contains(ConstantStr.CONNECTION) && errMsg.contains(ConstantStr.REFUSED));
        boolean readTimeOut = errMsg.contains("Read timed out");
        if (connectionRefused) {
          log.warn(errMsg);
        }
        else if (readTimeOut) {
          log.warn(errMsg);
        }
        else {
          log.error(errMsg);
        }
        return "请求失败";
      }
      finally {
        try {
          httpClient.close();
        }
        catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
  /**
   * HTTP协议GET请求方法
   */
  public static String httpMethodGet(String url, String gb) {
    if (null == gb || "".equals(gb)) {
      gb = "UTF-8";
    }
    StringBuilder sb = new StringBuilder();
    URL urls;
    HttpURLConnection uc = null;
    BufferedReader in = null;
    try {
      urls = new URL(url);
      uc = (HttpURLConnection) urls.openConnection();
      uc.setRequestMethod("GET");
      uc.connect();
      in = new BufferedReader(new InputStreamReader(uc.getInputStream(), gb));
      String readLine;
      while ((readLine = in.readLine()) != null) {
        sb.append(readLine);
      }
      in.close();
      uc.disconnect();
    }
    catch (Exception e) {
      log.error(e.getMessage(), e);
    }
    finally {
      if (uc != null) {
        uc.disconnect();
      }
    }
    return sb.toString();
  }
  /**
   * HTTP协议POST请求方法
   */
  public static String httpMethodPost(String url, String params, String gb) {
    if (null == gb || "".equals(gb)) {
      gb = "UTF-8";
    }
    StringBuilder sb = new StringBuilder();
    URL urls;
    HttpURLConnection uc = null;
    BufferedReader in;
    try {
      urls = new URL(url);
      uc = (HttpURLConnection) urls.openConnection();
      uc.setRequestMethod("POST");
      uc.setDoOutput(true);
      uc.setDoInput(true);
      uc.setUseCaches(false);
      uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
      uc.connect();
      DataOutputStream out = new DataOutputStream(uc.getOutputStream());
      out.write(params.getBytes(gb));
      out.flush();
      out.close();
      in = new BufferedReader(new InputStreamReader(uc.getInputStream(), gb));
      String readLine;
      while ((readLine = in.readLine()) != null) {
        sb.append(readLine);
      }
      in.close();
      uc.disconnect();
    }
    catch (IOException e) {
      log.error(e.getMessage(), e);
    }
    finally {
      if (uc != null) {
        uc.disconnect();
      }
    }
    return sb.toString();
  }
  /**
   * HTTP协议POST请求方法
   */
  public static String httpMethodPost(String url, TreeMap<String, String> paramsMap, String gb) {
    if (null == gb || "".equals(gb)) {
      gb = "UTF-8";
    }
    String params = null;
    if (null != paramsMap) {
      params = getParamStr(paramsMap);
    }
    // print("组装业务请求参数:" + params);
    StringBuilder sb = new StringBuilder();
    URL urls;
    HttpURLConnection uc = null;
    BufferedReader in;
    try {
      urls = new URL(url);
      uc = (HttpURLConnection) urls.openConnection();
      uc.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
      uc.setDoOutput(true);
      uc.setDoInput(true);
      uc.setRequestMethod("POST");
      uc.setUseCaches(false);
      uc.connect();
      DataOutputStream out = new DataOutputStream(uc.getOutputStream());
      if (params != null) {
        out.write(params.getBytes(gb));
      }
      out.flush();
      out.close();
      in = new BufferedReader(new InputStreamReader(uc.getInputStream(), gb));
      String readLine;
      while ((readLine = in.readLine()) != null) {
        sb.append(readLine);
      }
      in.close();
      uc.disconnect();
    }
    catch (IOException e) {
      log.error(e.getMessage(), e);
    }
    finally {
      if (uc != null) {
        uc.disconnect();
      }
    }
    return sb.toString();
  }
  /**
   * HTTP协议POST请求添加参数
   */
  private static String getParamStr(TreeMap<String, String> paramsMap) {
    StringBuilder param = new StringBuilder();
    for (Map.Entry<String, String> e : paramsMap.entrySet()) {
      param.append("&").append(e.getKey()).append("=").append(e.getValue());
    }
    return param.substring(1);
  }
  /**
   * 默认编码utf -8
   * Obtains character set of the entity, if known.
   *
   * @param entity must not be null
   * @return the character set, or null if not found
   * @throws ParseException           if header elements cannot be parsed
   * @throws IllegalArgumentException if entity is null
   */
  public static String getContentCharSet(final HttpEntity entity) throws ParseException {
    if (entity == null) {
      throw new IllegalArgumentException("HTTP entity may not be null");
    }
    String charset = null;
    if (entity.getContentType() != null) {
      HeaderElement[] values = entity.getContentType().getElements();
      if (values.length > 0) {
        NameValuePair param = values[0].getParameterByName("charset");
        if (param != null) {
          charset = param.getValue();
        }
      }
    }
    // print(charset);
    if (StringUtils.isEmpty(charset)) {
      // charset = "UTF-8";
      charset = "GB18030";
    }
    return charset;
  }
  /**
   * 获取重定向地址
   *
   * @param path String
   * @return String
   */
  public static String getRedirectUrl(String path) {
    try {
      HttpURLConnection conn = (HttpURLConnection) new URL(path).openConnection();
      conn.setInstanceFollowRedirects(false);
      conn.setConnectTimeout(5000);
      return conn.getHeaderField("Location");
    }
    catch (Exception e) {
      log.error(e.getMessage(), e);
      return e.getMessage();
    }
  }
}
